﻿using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using Log;

namespace RegLog
{
    /// <summary>
    /// Classe para registro de logs em arquivo XML.
    /// </summary>
    public class LogXML : ILog
    {
        /// <summary>
        /// Informa se o arquivo de log existente será ou não substituido.
        /// </summary>
        public bool SubstituirArquivo { get; set; }
        /// <summary>
        /// Nome do arquivo de log a ser utilizado.
        /// </summary>
        public string NomeArquivo { get; set; }

        private string caminhoArquivo;
        /// <summary>
        /// Caminho completo do repositório do arquivo de log.
        /// </summary>
        public string CaminhoArquivo 
        { 
            get 
            {
                return caminhoArquivo; 
            }
            set
            {
                caminhoArquivo = value;
                if (caminhoArquivo.LastIndexOf('\\') < caminhoArquivo.Length -1)
                    caminhoArquivo += "\\";
            } 
        }
        static XmlDocument logXML;
        static XmlTextWriter arquivoXML;
        
        /// <summary>
        /// Contrutor que define os dados do XML de log e seu método de gravação
        /// </summary>
        /// <param name="caminhoArquivo">Caminho onde o arquivo de log está gravado ou será criado.</param>
        /// <param name="nomeArquivo">Nome para o arquivo de log.</param>
        /// <param name="substituirArquivo">Define se o arquivo de log será substituido ou apenas incrementado. Utilize true para substituir o arquivo, o contrário para adicinoar registros ao arquivo existente.</param>
        public LogXML(string caminhoArquivo, string nomeArquivo, bool substituirArquivo)
        {
            NomeArquivo = nomeArquivo;
            CaminhoArquivo = caminhoArquivo;
            SubstituirArquivo = substituirArquivo;
        }

        /// <summary>
        /// Registrar o evento de log em XML.
        /// </summary>
        /// <param name="sender">Objeto gerador do registro de log.</param>
        /// <param name="e">Objeto que contém o log.</param>
        /// <param name="ret">Utilizado para retornar o resultado da execução à aplicação chamadora.</param>
        public void Log(object sender, EventosLogEventArgs e, out int ret)
        {
            if (SubstituirArquivo) File.Delete(CaminhoArquivo + NomeArquivo);
            if (!Directory.Exists(CaminhoArquivo)) Directory.CreateDirectory(CaminhoArquivo);
            if (!string.IsNullOrEmpty(CaminhoArquivo) && !string.IsNullOrEmpty(NomeArquivo))
            {
                try
                {
                    if (!File.Exists(CaminhoArquivo + NomeArquivo))
                    {
                        //File.Create(CaminhoArquivo + NomeArquivo).Close();
                        arquivoXML = new XmlTextWriter(CaminhoArquivo + NomeArquivo, System.Text.Encoding.UTF8);
                        arquivoXML.Formatting = Formatting.Indented;
                        arquivoXML.WriteStartDocument();
                        arquivoXML.WriteDocType("RegistroLog", "", "", "<!ELEMENT RegistroLog ANY>");
                        arquivoXML.WriteStartElement("RegistroLog");
                        arquivoXML.WriteEndElement(); //Log
                        arquivoXML.WriteEndDocument();
                        arquivoXML.Close();
                    }
                    logXML = new XmlDocument();
                    logXML.Load(CaminhoArquivo + NomeArquivo);
                    var tipoDocumento = logXML.DocumentType; //HACK Windows XP ou inferior não possui suporte
                    var root = logXML.DocumentElement;
                    XmlNode registro = logXML.CreateElement("Registro");
                    XmlNode dataHora = logXML.CreateElement("DataHora");
                    dataHora.InnerText = e.DataHora.ToString();
                    XmlNode tipo = logXML.CreateElement("Tipo");
                    tipo.InnerText = e.TipoLogString;
                    XmlNode descricao = logXML.CreateElement("Descricao");
                    descricao.InnerText = e.Descricao;
                    #region Dados da Exceção
                    XmlNode excecao = logXML.CreateElement("DadosExcecao");
                    XmlNode mensagem = logXML.CreateElement("Mensagem");
                    mensagem.InnerText = e.Exception.Message;
                    XmlNode source = logXML.CreateElement("Source");
                    source.InnerText = e.Exception.Source;
                    XmlNode stackTrace = logXML.CreateElement("StackTrace");
                    stackTrace.InnerText = e.Exception.StackTrace;
                    XmlNode targetSite = logXML.CreateElement("TargetSite");
                    targetSite.InnerText = e.Exception.TargetSite.ToString();
                    excecao.AppendChild(mensagem);
                    excecao.AppendChild(source);
                    excecao.AppendChild(stackTrace);
                    excecao.AppendChild(targetSite);
                    #endregion
                    registro.AppendChild(dataHora);
                    registro.AppendChild(tipo);
                    registro.AppendChild(descricao);
                    registro.AppendChild(excecao);
                    root.AppendChild(registro);
                    logXML.Save(CaminhoArquivo + NomeArquivo);
                    ret = 0;
                }
                catch (Exception ex)
                {
                    ret = -1;
                    throw ex;
                }
            }
            else
            {
                ret = -1;
                throw new Exception("Arquivo de log não encontrado");
            }
        }
    }
}
